const axios = require('axios');
const sha1 = require('sha1');
const TicketModel = require('../db/models/ticketModel');
const { AppID, AppSecret } = require('../config');

// https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

/**
 * 获取 ticket
 * @returns ticket
 */
const getTicket = async () => {
    let tik_data = await TicketModel.find();
    let access_token = '';
    let ticket = '';

    if (tik_data.length > 0) { // 判断数据库是否存储过 ticket
        let t = Date.now() - tik_data[0].token_time;
        if (t > 7000000) { // 判断是否过期
            // 重新获取
            await loadData();
            let { _id } = tik_data[0];
            let cur_time = Date.now()
            await TicketModel.update({ _id }, { // 更新数据库中已过期的数据
                access_token,
                token_time: cur_time,
                ticket,
                ticket_time: cur_time
            })
        } else {
            // 用数据库中的数据
            access_token = tik_data[0].access_token;
            ticket = tik_data[0].ticket;
        }
    } else { // 重新获取
        await loadData();
        let cur_time = Date.now()
        await new TicketModel({ // 如果是第一次获取 access_token，则对数据库进行新增操作
            access_token,
            token_time: cur_time,
            ticket,
            ticket_time: cur_time
        }).save()
    }

    async function loadData() {
        let tokenUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${AppID}&secret=${AppSecret}`;
        let token_data = await axios.get(tokenUrl);
        // console.log(token_data);
        access_token = token_data.data.access_token; // 得到 access_token
        console.log('access_token', access_token);

        let ticketUrl = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${access_token}&type=jsapi`;
        let ticket_data = await axios.get(ticketUrl); // 得到 jsapi_ticket
        console.log('ticket', ticket_data.data.ticket);
        ticket = ticket_data.data.ticket;
    }

    return {
        access_token,
        ticket
    }
};

/**
 * 生成随机字符串
 * @returns noncestr
 */
const createNonceStr = () => {
    return Math.random().toString(36).substr(2, 15);
}

/**
 * 生成时间戳
 * @returns timestamp
 */
const createTimestamp = () => {
    return parseInt(new Date().getTime() / 1000) + '';
}

/**
 * 处理数据格式的方法函数
 */
const row = (obj) => {
    let keys = Object.keys(obj);
    keys = keys.sort() //字典排序
    let newObj = {};
    keys.forEach((key) => {
        newObj[key.toLowerCase()] = obj[key]
    })
    let string = '';
    for (let k in newObj) {
        string += '&' + k + '=' + newObj[k]
    }
    string = string.substr(1)
    return string;
}

/**
 * 生成 signature 签名等数据信息的方法
 * @param {} url 
 */
const sign = async (url) => {
    let { ticket: jsapi_ticket } = await getTicket();
    let obj = {
        jsapi_ticket,
        nonceStr: createNonceStr(),
        timestamp: createTimestamp(),
        url
    }

    let str = row(obj);
    let signature = sha1(str); //生成签名
    obj.signature = signature;
    obj.appId = AppID;

    /**
    1. 签名生成规则如下：参与签名的字段包括noncestr（随机字符串）, 
    有效的jsapi_ticket, timestamp（时间戳）, 
    url（当前网页的URL，不包含#及其后面部分） 。
    2. 对所有待签名参数按照字段名的ASCII 码从小到大排序（字典序）后，
    3. 使用URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串string1。
    这里需要注意的是所有参数名均为小写字符。对string1作sha1加密，字
    段名和字段值都采用原始值，不进行URL 转义。
    
    即signature=sha1(string1)。 示例： 
     */
    return obj;
}

module.exports = sign;
